added Feb 2001 SDK
[windows-sources.git] / shared source / sscli20 / jscript / engine / binding.cs
blobe801ab58d8740bfe947d79f68ba3c8acf375a747
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 namespace Microsoft.JScript {
18 using System;
19 using System.Collections;
20 using System.Globalization;
21 using System.Reflection;
22 using System.Reflection.Emit;
24 public abstract class Binding : AST{
25 private IReflect[] argIRs;
26 protected MemberInfo defaultMember;
27 private IReflect defaultMemberReturnIR;
28 private bool isArrayElementAccess;
29 private bool isArrayConstructor;
30 protected bool isAssignmentToDefaultIndexedProperty;
31 protected bool isFullyResolved;
32 protected bool isNonVirtual;
33 internal MemberInfo[] members;
34 internal MemberInfo member;
35 protected String name;
36 private bool giveErrors;
38 static internal ConstantWrapper ReflectionMissingCW = new ConstantWrapper(System.Reflection.Missing.Value, null);
39 static private ConstantWrapper JScriptMissingCW = new ConstantWrapper(Missing.Value, null);
41 internal Binding(Context context, String name)
42 : base(context) {
43 this.argIRs = null;
44 this.defaultMember = null;
45 this.defaultMemberReturnIR = null;
46 this.isArrayElementAccess = false;
47 this.isArrayConstructor = false;
48 this.isAssignmentToDefaultIndexedProperty = false;
49 this.isFullyResolved = true;
50 this.isNonVirtual = false;
51 this.members = null;
52 this.member = null;
53 this.name = name;
54 this.giveErrors = true;
57 private bool Accessible(bool checkSetter){
58 if (this.member == null) return false;
59 switch(this.member.MemberType){
60 case MemberTypes.Constructor: return AccessibleConstructor();
61 case MemberTypes.Event: return false;
62 case MemberTypes.Field: return AccessibleField(checkSetter);
63 case MemberTypes.Method: return AccessibleMethod();
64 case MemberTypes.NestedType:
65 if (!((Type)this.member).IsNestedPublic){
66 if (this.giveErrors)
67 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
68 return false;
70 if(checkSetter)
71 return false;
72 return true;
73 case MemberTypes.TypeInfo:
74 if (!((Type)this.member).IsPublic){
75 if (this.giveErrors)
76 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
77 return false;
79 if(checkSetter)
80 return false;
81 return true;
82 case MemberTypes.Property: return AccessibleProperty(checkSetter);
84 return false;
87 private bool AccessibleConstructor(){
88 ConstructorInfo cons = (ConstructorInfo)this.member;
89 if ((cons is JSConstructor && ((JSConstructor)member).GetClassScope().owner.isAbstract) ||
90 (!(cons is JSConstructor) && cons.DeclaringType.IsAbstract)){
91 this.context.HandleError(JSError.CannotInstantiateAbstractClass);
92 return false;
94 if (cons.IsPublic) return true;
95 if (cons is JSConstructor){
96 if (((JSConstructor)cons).IsAccessibleFrom(Globals.ScopeStack.Peek())) return true;
98 if (this.giveErrors)
99 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
100 return false;
103 private bool AccessibleField(bool checkWritable){
104 FieldInfo field = (FieldInfo)this.member;
105 if (checkWritable && (field.IsInitOnly || field.IsLiteral)) return false;
106 if (!field.IsPublic){
107 JSWrappedField wfield = field as JSWrappedField;
108 if (wfield != null)
109 this.member = field = wfield.wrappedField;
110 JSClosureField cfield = field as JSClosureField;
111 JSMemberField mfield = (cfield != null ? cfield.field : field) as JSMemberField;
112 if (mfield == null){
113 if ((!field.IsFamily && !field.IsFamilyOrAssembly) || !Binding.InsideClassThatExtends(Globals.ScopeStack.Peek(), field.ReflectedType)){
114 if (this.giveErrors)
115 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
116 return false;
118 }else if (!mfield.IsAccessibleFrom(Globals.ScopeStack.Peek())){
119 if (this.giveErrors)
120 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
121 return false;
124 if (field.IsLiteral && field is JSVariableField){
125 ClassScope csc = ((JSVariableField)field).value as ClassScope;
126 if (csc != null && !csc.owner.IsStatic){
127 Lookup lookup = this as Lookup;
128 if (lookup == null || !lookup.InStaticCode() || lookup.InFunctionNestedInsideInstanceMethod()) return true;
129 if (this.giveErrors)
130 this.context.HandleError(JSError.InstanceNotAccessibleFromStatic, this.isFullyResolved);
131 return true;
134 if (field.IsStatic || field.IsLiteral || this.defaultMember != null || !(this is Lookup) || !((Lookup)this).InStaticCode()) return true;
135 if (field is JSWrappedField && field.DeclaringType == Typeob.LenientGlobalObject) return true;
136 if (this.giveErrors) {
137 if (!field.IsStatic && this is Lookup && ((Lookup)this).InStaticCode())
138 this.context.HandleError(JSError.InstanceNotAccessibleFromStatic, this.isFullyResolved);
139 else
140 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
142 return false;
145 private bool AccessibleMethod(){
146 MethodInfo meth = (MethodInfo)this.member;
147 return this.AccessibleMethod(meth);
150 private bool AccessibleMethod(MethodInfo meth){
151 if (meth == null) return false;
152 if (this.isNonVirtual && meth.IsAbstract){
153 this.context.HandleError(JSError.InvalidCall);
154 return false;
156 if (!meth.IsPublic){
157 JSWrappedMethod wmeth = meth as JSWrappedMethod;
158 if (wmeth != null)
159 meth = wmeth.method;
160 JSClosureMethod cmeth = meth as JSClosureMethod;
161 JSFieldMethod fmeth = (cmeth != null ? cmeth.method : meth) as JSFieldMethod;
162 if (fmeth == null){
163 if ((meth.IsFamily || meth.IsFamilyOrAssembly) && Binding.InsideClassThatExtends(Globals.ScopeStack.Peek(), meth.ReflectedType))
164 return true;
165 if (this.giveErrors)
166 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
167 return false;
168 }else if (!fmeth.IsAccessibleFrom(Globals.ScopeStack.Peek())){
169 if (this.giveErrors)
170 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
171 return false;
174 if (meth.IsStatic || this.defaultMember != null || !(this is Lookup) || !((Lookup)this).InStaticCode()) return true;
175 if (meth is JSWrappedMethod && ((Lookup)this).CanPlaceAppropriateObjectOnStack(((JSWrappedMethod)meth).obj)) return true;
176 if (this.giveErrors) {
177 if (!meth.IsStatic && this is Lookup && ((Lookup)this).InStaticCode())
178 this.context.HandleError(JSError.InstanceNotAccessibleFromStatic, this.isFullyResolved);
179 else
180 this.context.HandleError(JSError.NotAccessible, this.isFullyResolved);
182 return false;
185 private bool AccessibleProperty(bool checkSetter){
186 PropertyInfo prop = (PropertyInfo)this.member;
187 if (this.AccessibleMethod(checkSetter ? JSProperty.GetSetMethod(prop, true) : JSProperty.GetGetMethod(prop, true))) return true;
188 if (this.giveErrors && !checkSetter) this.context.HandleError(JSError.WriteOnlyProperty);
189 return false;
192 internal static bool AssignmentCompatible(IReflect lhir, AST rhexpr, IReflect rhir, bool reportError){
193 if (rhexpr is ConstantWrapper){
194 Object rhval = rhexpr.Evaluate();
195 if (rhval is ClassScope){
196 if (lhir == Typeob.Type || lhir == Typeob.Object || lhir == Typeob.String) return true;
197 else{
198 if (reportError) rhexpr.context.HandleError(JSError.TypeMismatch);
199 return false;
202 ClassScope csc = lhir as ClassScope;
203 if (csc != null){
204 EnumDeclaration ed = csc.owner as EnumDeclaration;
205 if (ed != null){
206 ConstantWrapper cw = rhexpr as ConstantWrapper;
207 if (cw != null && cw.value is String){
208 FieldInfo field = csc.GetField((String)cw.value, BindingFlags.Public|BindingFlags.Static);
209 if (field == null) return false;
210 ed.PartiallyEvaluate();
211 cw.value = new DeclaredEnumValue(((JSMemberField)field).value, field.Name, csc);
213 if (rhir == Typeob.String) return true;
214 lhir = ed.baseType.ToType();
216 } else if (lhir is Type) {
217 Type type = lhir as Type;
218 if (type.IsEnum) {
219 ConstantWrapper cw = rhexpr as ConstantWrapper;
220 if (cw != null && cw.value is String){
221 FieldInfo field = type.GetField((String)cw.value, BindingFlags.Public|BindingFlags.Static);
222 if (field == null) return false;
223 cw.value = MetadataEnumValue.GetEnumValue(field.FieldType, field.GetRawConstantValue());
225 if (rhir == Typeob.String) return true;
226 lhir = Enum.GetUnderlyingType(type);
230 if (lhir is Type){
231 try{
232 Convert.CoerceT(rhval, (Type)lhir);
233 return true;
234 }catch{
235 if (lhir == Typeob.Single && rhval is Double){
236 if (((ConstantWrapper)rhexpr).isNumericLiteral) return true;
237 Double d = (Double)rhval;
238 Single s = (Single)d;
239 if (d.ToString(CultureInfo.InvariantCulture).Equals(s.ToString(CultureInfo.InvariantCulture))){
240 ((ConstantWrapper)rhexpr).value = s;
241 return true;
244 if (lhir == Typeob.Decimal){
245 ConstantWrapper cw = rhexpr as ConstantWrapper;
246 if (cw != null && cw.isNumericLiteral){
247 try{
248 Convert.CoerceT(cw.context.GetCode(), Typeob.Decimal);
249 return true;
250 }catch{}
253 if (reportError)
254 rhexpr.context.HandleError(JSError.TypeMismatch);
256 return false;
258 }else if (rhexpr is ArrayLiteral)
259 return ((ArrayLiteral)rhexpr).AssignmentCompatible(lhir, reportError);
260 if (rhir == Typeob.Object) return true; //Too little is known about the expression to complain at compile time
261 if (rhir == Typeob .Double && Convert.IsPrimitiveNumericType(lhir)) return true; //Arithmetic expressions infer to Double, but might have the right result.
262 if (lhir is Type && Typeob.Delegate.IsAssignableFrom((Type)lhir) && rhir == Typeob.ScriptFunction &&
263 rhexpr is Binding && ((Binding)rhexpr).IsCompatibleWithDelegate((Type)lhir))
264 return true;
265 if (Convert.IsPromotableTo(rhir, lhir))
266 return true; //rhexpr delivers a value that can be converted to something expected by the assignment target
267 if (Convert.IsJScriptArray(rhir) && Binding.ArrayAssignmentCompatible(rhexpr, lhir))
268 return true;
269 if (lhir == Typeob.String)
270 return true; // Everything is assignment-compatible to string.
271 if (rhir == Typeob.String && (lhir == Typeob.Boolean || Convert.IsPrimitiveNumericType(lhir))){
272 if (reportError) rhexpr.context.HandleError(JSError.PossibleBadConversionFromString);
273 return true;
275 if ((lhir == Typeob.Char && rhir == Typeob.String) || Convert.IsPromotableTo(lhir, rhir) ||
276 (Convert.IsPrimitiveNumericType(lhir) && Convert.IsPrimitiveNumericType(rhir))){
277 if (reportError) rhexpr.context.HandleError(JSError.PossibleBadConversion);
278 return true;
281 if (reportError)
282 rhexpr.context.HandleError(JSError.TypeMismatch);
283 return false;
286 private static bool ArrayAssignmentCompatible(AST ast, IReflect lhir){
287 // If we've made it here then we already know that lhir is not Object or String
288 // and that a JScript array is not promotable to lhir. There are cases where
289 // a JScript array is not promotable but is assignable with a warning. A
290 // JScript array is assignable to a System.Array or to a rank-one typed array.
291 if (!Convert.IsArray(lhir))
292 return false;
293 else if (lhir == Typeob.Array){
294 ast.context.HandleError(JSError.ArrayMayBeCopied);
295 return true;
296 }else if (Convert.GetArrayRank(lhir) == 1){
297 ast.context.HandleError(JSError.ArrayMayBeCopied);
298 return true;
299 }else
300 return false;
303 internal void CheckIfDeletable(){
304 if (this.member != null || this.defaultMember != null)
305 this.context.HandleError(JSError.NotDeletable);
306 this.member = null;
307 this.defaultMember = null;
310 internal void CheckIfUseless(){
311 // This is called for expression statements. There are no cases where an
312 // expression which just retrieves a property should not give a warning.
313 // We don't bother giving a warning if members is empty because more than
314 // likely an warning or error was already issued.
315 if (this.members == null || this.members.Length == 0)
316 return;
317 this.context.HandleError(JSError.UselessExpression);
320 internal static bool CheckParameters(ParameterInfo[] pars, IReflect[] argIRs, ASTList argAST, Context ctx){
321 return Binding.CheckParameters(pars, argIRs, argAST, ctx, 0, false, true);
324 internal static bool CheckParameters(ParameterInfo[] pars, IReflect[] argIRs, ASTList argAST, Context ctx, int offset, bool defaultIsUndefined, bool reportError){
325 int n = argIRs.Length;
326 int m = pars.Length;
327 bool tooManyParams = false;
328 if (n > m-offset) {n = m-offset; tooManyParams = true;}
329 for (int i = 0; i < n; i++){
330 IReflect formalIR = (pars[i+offset] is ParameterDeclaration) ? ((ParameterDeclaration)pars[i+offset]).ParameterIReflect : pars[i+offset].ParameterType;
331 IReflect actualIR = argIRs[i];
332 if (i == n-1 && ((formalIR is Type && Typeob.Array.IsAssignableFrom((Type)formalIR)) || formalIR is TypedArray) &&
333 CustomAttribute.IsDefined(pars[i+offset], typeof(ParamArrayAttribute), false)){
334 tooManyParams = false;
335 int k = argIRs.Length;
336 if (i == k - 1){
337 if (Binding.AssignmentCompatible(formalIR, argAST[i], argIRs[i], false))
338 return true;
340 IReflect elemIR = formalIR is Type ? ((Type)formalIR).GetElementType() : ((TypedArray)formalIR).elementType;
341 for (int j = i; j < k; j++)
342 if (!Binding.AssignmentCompatible(elemIR, argAST[j], argIRs[j], reportError)) return false;
343 return true;
345 if (!Binding.AssignmentCompatible(formalIR, argAST[i], actualIR, reportError)) return false;
347 if (tooManyParams && reportError)
348 ctx.HandleError(JSError.TooManyParameters);
349 if (offset == 0 && n < m && !defaultIsUndefined) //Fewer actual parameters than formal parameters
350 for (int j = n; j < m; j++)
351 if (TypeReferences.GetDefaultParameterValue(pars[j]) == System.Convert.DBNull){ //No default value specified
352 //Ensure that custom attribute has been resolved before checking
353 ParameterDeclaration pardecl = pars[j] as ParameterDeclaration;
354 if (pardecl != null)
355 pardecl.PartiallyEvaluate();
356 if (j < m-1 || !CustomAttribute.IsDefined(pars[j], typeof(ParamArrayAttribute), false)){
357 if (reportError)
358 ctx.HandleError(JSError.TooFewParameters);
359 IReflect formalIR = (pars[j+offset] is ParameterDeclaration) ? ((ParameterDeclaration)pars[j+offset]).ParameterIReflect : pars[j+offset].ParameterType;
360 Type formalType = formalIR as Type;
361 if (formalType != null && formalType.IsValueType && !formalType.IsPrimitive && !formalType.IsEnum)
362 return false; //Can't generate valid code for this since there is no general mapping from undefined to value types
365 return true;
368 internal override bool Delete(){
369 return this.EvaluateAsLateBinding().Delete();
372 internal override Object Evaluate(){
373 Object ob = this.GetObject();
374 MemberInfo member = this.member;
375 if (member != null)
376 switch(member.MemberType){
377 case MemberTypes.Field : return ((FieldInfo)member).GetValue(ob);
378 case MemberTypes.Property :
379 MemberInfo[] members = new MemberInfo[]{JSProperty.GetGetMethod((PropertyInfo)member, false)};
380 return LateBinding.CallOneOfTheMembers(members, new Object[0], false, ob, null, null, null, this.Engine);
381 case MemberTypes.Event : return null;
382 case MemberTypes.NestedType : return member;
384 if (this.members != null && this.members.Length > 0){
385 //Special case check for methods on builtin objects
386 if (this.members.Length == 1 && this.members[0].MemberType == MemberTypes.Method){
387 MethodInfo meth = (MethodInfo)members[0];
388 Type dt = meth is JSMethod ? null : meth.DeclaringType;
390 if (dt == Typeob.GlobalObject ||
391 (dt != null && dt != Typeob.StringObject && dt != Typeob.NumberObject && dt != Typeob.BooleanObject && dt.IsSubclassOf(Typeob.JSObject))){
392 //This only happens in fast mode. We could add InitOnly fields to the fast predefined objects and initialize them
393 //with instances of BuiltinFunction objects, in which case we would never get here, but we would like to avoid
394 //the start up cost of allocating these objects, particularly if they end up never being used (the expected common case).
395 return Globals.BuiltinFunctionFor(ob, TypeReferences.ToExecutionContext(meth));
396 //Note that meth is not wrapped because it is static
400 return new FunctionWrapper(this.name, ob, this.members);
402 return this.EvaluateAsLateBinding().GetValue();
405 //Returns a list of member infos that are sorted by declaring type. Superclass members always follow derived class members.
406 private MemberInfoList GetAllKnownInstanceBindingsForThisName(){
407 IReflect[] classes = this.GetAllEligibleClasses();
408 MemberInfoList result = new MemberInfoList();
409 foreach (IReflect c in classes){
410 if (c is ClassScope){
411 if (((ClassScope)c).ParentIsInSamePackage())
412 result.AddRange(c.GetMember(name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.DeclaredOnly));
413 else
414 result.AddRange(c.GetMember(name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance));
415 }else
416 result.AddRange(c.GetMember(name, BindingFlags.Public|BindingFlags.Instance));
418 return result;
421 //Returns a list of the classes visible from the current scope.
422 //Currently, classes are returned only if they are ancestors of the current class, or reside in the same package.
423 private IReflect[] GetAllEligibleClasses(){
424 ArrayList classes = new ArrayList(16);
425 ClassScope currentClass = null;
426 PackageScope currentPackage = null;
427 ScriptObject scope = Globals.ScopeStack.Peek();
428 while (scope is WithObject || scope is BlockScope)
429 scope = scope.GetParent();
430 if (scope is FunctionScope)
431 scope = ((FunctionScope)scope).owner.enclosing_scope;
432 if (scope is ClassScope){
433 currentClass = (ClassScope)scope;
434 currentPackage = currentClass.package;
436 if (currentClass != null)
437 currentClass.AddClassesFromInheritanceChain(this.name, classes);
438 if (currentPackage != null)
439 currentPackage.AddClassesExcluding(currentClass, this.name, classes);
440 else
441 ((IActivationObject)scope).GetGlobalScope().AddClassesExcluding(currentClass, this.name, classes);
442 IReflect[] result = new IReflect[classes.Count]; classes.CopyTo(result);
443 return result;
446 protected abstract Object GetObject();
448 protected abstract void HandleNoSuchMemberError();
450 internal override IReflect InferType(JSField inference_target){
451 Debug.Assert(this.members != null); //Have to call a PartiallyEvaluate routine before calling InferType
452 if (this.isArrayElementAccess){
453 IReflect ir = this.defaultMemberReturnIR;
454 return ir is TypedArray ? ((TypedArray)ir).elementType : ((Type)ir).GetElementType();
456 if (this.isAssignmentToDefaultIndexedProperty){
457 if (this.member is PropertyInfo) //Could be null if no binding was found
458 return ((PropertyInfo)this.member).PropertyType;
459 return Typeob.Object;
461 MemberInfo member = this.member;
462 if (member is FieldInfo){
463 JSWrappedField wf = member as JSWrappedField;
464 if (wf != null) member = wf.wrappedField;
465 if (member is JSVariableField)
466 return ((JSVariableField)member).GetInferredType(inference_target);
467 else
468 return ((FieldInfo)member).FieldType;
470 if (member is PropertyInfo) {
471 JSWrappedProperty wp = member as JSWrappedProperty;
472 if (wp != null) member = wp.property;
473 if (member is JSProperty)
474 return ((JSProperty)member).PropertyIR();
475 else{
476 PropertyInfo prop = (PropertyInfo)member;
477 if (prop.DeclaringType == Typeob.GlobalObject)
478 return (IReflect)prop.GetValue(this.Globals.globalObject, null);
479 else
480 return prop.PropertyType;
484 if (member is Type)
485 return Typeob.Type;
486 if (member is EventInfo)
487 return Typeob.EventInfo;
488 if (this.members.Length > 0 && this.Engine.doFast)
489 return Typeob.ScriptFunction;
490 return Typeob.Object;
493 internal virtual IReflect InferTypeOfCall(JSField inference_target, bool isConstructor){
494 Debug.Assert(this.members != null); //Have to call a PartiallyEvaluate routine before calling InferTypeOfCall
495 if (!this.isFullyResolved) return Typeob.Object;
496 if (this.isArrayConstructor)
497 return this.defaultMemberReturnIR;
498 if (this.isArrayElementAccess){
499 IReflect ir = this.defaultMemberReturnIR;
500 return ir is TypedArray ? ((TypedArray)ir).elementType : ((Type)ir).GetElementType();
502 MemberInfo member = this.member;
503 if (member is JSFieldMethod) return isConstructor ? Typeob.Object : ((JSFieldMethod)member).ReturnIR();
504 if (member is MethodInfo) return ((MethodInfo)member).ReturnType;
505 if (member is JSConstructor) return ((JSConstructor)member).GetClassScope();
506 if (member is ConstructorInfo) return ((ConstructorInfo)member).DeclaringType;
507 if (member is Type) return (Type)member;
508 if (member is FieldInfo && ((FieldInfo)member).IsLiteral){
509 Object val = member is JSVariableField ? ((JSVariableField)member).value : TypeReferences.GetConstantValue((FieldInfo)member);
510 if (val is ClassScope || val is TypedArray) return (IReflect)val;
512 return Typeob.Object;
515 private static bool InsideClassThatExtends(ScriptObject scope, Type type){
516 while (scope is WithObject || scope is BlockScope)
517 scope = scope.GetParent();
518 if (scope is ClassScope)
519 return type.IsAssignableFrom(((ClassScope)scope).GetBakedSuperType());
520 if (scope is FunctionScope)
521 return Binding.InsideClassThatExtends(((FunctionScope)scope).owner.enclosing_scope, type);
522 //Eval does not see non public members, so don't worry about StackFrame
523 return false;
526 internal void InvalidateBinding(){
527 this.isAssignmentToDefaultIndexedProperty = false;
528 this.isArrayConstructor = false;
529 this.isArrayElementAccess = false;
530 this.defaultMember = null;
531 this.member = null;
532 this.members = new MemberInfo[0];
535 internal bool IsCompatibleWithDelegate(Type delegateType){
536 Debug.Assert(this.members != null && this.members.Length > 0);
537 MethodInfo invoke = delegateType.GetMethod("Invoke");
538 ParameterInfo[] dparams = invoke.GetParameters();
539 Type drtype = invoke.ReturnType;
540 foreach (MemberInfo mem in this.members){
541 if (mem is MethodInfo){
542 MethodInfo meth = (MethodInfo)mem;
543 Type returnType = null;
544 if (meth is JSFieldMethod){
545 IReflect returnIR = ((JSFieldMethod)meth).ReturnIR();
546 if (returnIR is ClassScope)
547 returnType = ((ClassScope)returnIR).GetBakedSuperType(); //JScript cannot define delegates, so baked is OK.
548 else if (returnIR is Type)
549 returnType = (Type)returnIR;
550 else
551 returnType = Convert.ToType(returnIR);
552 if (((JSFieldMethod)meth).func.isExpandoMethod) return false;
553 }else
554 returnType = meth.ReturnType;
555 if (returnType == drtype && Class.ParametersMatch(dparams, meth.GetParameters())){
556 this.member = meth;
557 this.isFullyResolved = true;
558 return true;
562 return false;
565 public static bool IsMissing(Object value){
566 return value is Missing;
569 private MethodInfo LookForParameterlessPropertyGetter(){
570 // We only get here as a result of an AmbiguousMatchException. If all the matches are parameterless
571 // property getters, we try selecting a match without providing arguments.
572 for (int i=0, n=this.members.Length; i<n; i++){
573 PropertyInfo prop = this.members[i] as PropertyInfo;
574 if (prop != null){
575 MethodInfo meth = prop.GetGetMethod(true);
576 if (meth == null) continue;
577 ParameterInfo[] parameters = meth.GetParameters();
578 if (parameters == null || parameters.Length == 0) continue;
580 return null;
582 try{
583 MethodInfo meth = JSBinder.SelectMethod(this.members, new IReflect[0]); //Returns property getters as well
584 if (meth != null && meth.IsSpecialName){ //Property getter.
585 return meth;
587 }catch(AmbiguousMatchException){
589 return null;
592 internal override bool OkToUseAsType(){
593 MemberInfo member = this.member;
594 if (member is Type) return this.isFullyResolved = true;
595 if (member is FieldInfo){
596 FieldInfo field = (FieldInfo)member;
597 if (field.IsLiteral){
598 if (field is JSMemberField && ((JSMemberField)field).value is ClassScope && !field.IsStatic)
599 return false;
600 return this.isFullyResolved = true;
602 if (!(member is JSField) && field.IsStatic && field.GetValue(null) is Type) return this.isFullyResolved = true;
604 return false;
607 private int PlaceValuesForHiddenParametersOnStack(ILGenerator il, MethodInfo meth, ParameterInfo[] pars){
608 int offset = 0;
609 if (meth is JSFieldMethod){
610 FunctionObject func = ((JSFieldMethod)meth).func;
611 if (func != null && func.isMethod) return 0;
612 if (this is Lookup)
613 ((Lookup)this).TranslateToILDefaultThisObject(il);
614 else
615 this.TranslateToILObject(il, Typeob.Object, false);
616 this.EmitILToLoadEngine(il);
617 return 0;
619 Object[] attrs = CustomAttribute.GetCustomAttributes(meth, typeof(JSFunctionAttribute), false);
620 if (attrs == null || attrs.Length == 0) return 0;
621 JSFunctionAttributeEnum attr = ((JSFunctionAttribute)attrs[0]).attributeValue;
622 if ((attr & JSFunctionAttributeEnum.HasThisObject) != 0){
623 offset = 1;
624 Type pt = pars[0].ParameterType;
625 if (this is Lookup && pt == Typeob.Object)
626 ((Lookup)this).TranslateToILDefaultThisObject(il);
627 else {
628 if (Typeob.ArrayObject.IsAssignableFrom(member.DeclaringType))
629 this.TranslateToILObject(il, Typeob.ArrayObject, false);
630 else
631 this.TranslateToILObject(il, pt, false);
634 if ((attr & JSFunctionAttributeEnum.HasEngine) != 0){
635 offset += 1;
636 this.EmitILToLoadEngine(il);
638 return offset;
641 private bool ParameterlessPropertyValueIsCallable(MethodInfo meth, ASTList args, IReflect[] argIRs, bool constructor, bool brackets){
642 ParameterInfo[] pars = meth.GetParameters();
643 if (pars == null || pars.Length == 0){
644 if ((meth is JSWrappedMethod && ((JSWrappedMethod)meth).GetWrappedObject() is GlobalObject) ||
645 argIRs.Length > 0 ||
646 (!(meth is JSMethod) && Typeob.ScriptFunction.IsAssignableFrom(meth.ReturnType))){
647 this.member = this.ResolveOtherKindOfCall(args, argIRs, constructor, brackets);
648 return true;
650 IReflect mrt = meth is JSFieldMethod ? ((JSFieldMethod)meth).ReturnIR() : meth.ReturnType;
651 if (mrt != Typeob.Object && mrt != Typeob.ScriptFunction)
652 this.context.HandleError(JSError.InvalidCall);
653 else{
654 this.member = this.ResolveOtherKindOfCall(args, argIRs, constructor, brackets);
655 return true;
658 return false;
661 internal static void PlaceArgumentsOnStack(ILGenerator il, ParameterInfo[] pars, ASTList args, int offset, int rhoffset, AST missing){
662 int k = args.count;
663 int n = k+offset;
664 int m = pars.Length-rhoffset;
665 bool varargs = m > 0 && CustomAttribute.IsDefined(pars[m-1], typeof(ParamArrayAttribute), false) &&
666 !(k == m && Convert.IsArrayType(args[k-1].InferType(null)));
667 Type varargElemType = varargs ? pars[--m].ParameterType.GetElementType() : null;
668 if (n > m) n = m;
669 for (int i = offset; i < n; i++){
670 Type ptype = pars[i].ParameterType;
671 AST arg = args[i-offset];
672 if (arg is ConstantWrapper && ((ConstantWrapper)arg).value == System.Reflection.Missing.Value){
673 Object defVal = TypeReferences.GetDefaultParameterValue(pars[i]);
674 ((ConstantWrapper)arg).value = defVal != System.Convert.DBNull ? defVal : null;
676 if (ptype.IsByRef)
677 arg.TranslateToILReference(il, ptype.GetElementType());
678 else
679 arg.TranslateToIL(il, ptype);
681 if (n < m){
682 for (int i = n; i < m; i++){
683 Type ptype = pars[i].ParameterType;
684 if (TypeReferences.GetDefaultParameterValue(pars[i]) == System.Convert.DBNull) //No default value was specified
685 if (ptype.IsByRef)
686 missing.TranslateToILReference(il, ptype.GetElementType());
687 else
688 missing.TranslateToIL(il, ptype);
689 else
690 if (ptype.IsByRef)
691 (new ConstantWrapper(TypeReferences.GetDefaultParameterValue(pars[i]), null)).TranslateToILReference(il, ptype.GetElementType());
692 else
693 (new ConstantWrapper(TypeReferences.GetDefaultParameterValue(pars[i]), null)).TranslateToIL(il, ptype);
696 if (varargs){
697 n -= offset; //The number of arguments in argList that are already on the stack
698 m = k>n ? k-n : 0; //The number of arguments in argList that are to be placed in the vararg array
699 ConstantWrapper.TranslateToILInt(il, m);
700 il.Emit(OpCodes.Newarr, varargElemType);
701 bool doLdelema = varargElemType.IsValueType && !varargElemType.IsPrimitive;
702 for (int i = 0; i < m; i++){
703 il.Emit(OpCodes.Dup);
704 ConstantWrapper.TranslateToILInt(il, i);
705 if (doLdelema)
706 il.Emit(OpCodes.Ldelema, varargElemType);
707 args[i+n].TranslateToIL(il, varargElemType);
708 Binding.TranslateToStelem(il, varargElemType);
713 internal bool RefersToMemoryLocation(){
714 if (this.isFullyResolved){
715 if (this.isArrayElementAccess) return true;
716 return this.member is FieldInfo;
718 return false;
721 internal override void ResolveCall(ASTList args, IReflect[] argIRs, bool constructor, bool brackets){
722 this.argIRs = argIRs;
723 if (this.members == null || this.members.Length == 0){
724 if (constructor && this.isFullyResolved && this.Engine.doFast)
725 if (this.member != null && (this.member is Type || (this.member is FieldInfo && ((FieldInfo)this.member).IsLiteral)))
726 this.context.HandleError(JSError.NoConstructor);
727 else
728 this.HandleNoSuchMemberError();
729 else
730 this.HandleNoSuchMemberError();
731 return; //Have to do a runtime lookup
733 MemberInfo member = null;
734 if (!(this is CallableExpression) && !(constructor && brackets))
735 try{
736 if (constructor)
737 this.member = member = JSBinder.SelectConstructor(this.members, argIRs);
738 else{
739 MethodInfo meth;
740 this.member = member = meth = JSBinder.SelectMethod(this.members, argIRs); //Returns property getters as well
741 if (meth != null && meth.IsSpecialName){ //Property getter.
742 if (this.name == meth.Name){
743 if (this.name.StartsWith("get_", StringComparison.Ordinal) || this.name.StartsWith("set_", StringComparison.Ordinal)){
744 this.context.HandleError(JSError.NotMeantToBeCalledDirectly);
745 this.member = null;
746 return;
748 }else if (this.ParameterlessPropertyValueIsCallable(meth, args, argIRs, constructor, brackets))
749 return; // this.member was set by ParameterlessPropertyValueIsCallable
752 }catch(AmbiguousMatchException){
753 if (constructor)
754 this.context.HandleError(JSError.AmbiguousConstructorCall, this.isFullyResolved);
755 else{
756 MethodInfo meth = this.LookForParameterlessPropertyGetter();
757 if (meth != null && this.ParameterlessPropertyValueIsCallable(meth, args, argIRs, constructor, brackets))
758 return; // this.member was set by ParameterlessPropertyValueIsCallable
759 this.context.HandleError(JSError.AmbiguousMatch, this.isFullyResolved);
760 this.member = null;
762 return;
763 }catch(JScriptException e){
764 this.context.HandleError((Microsoft.JScript.JSError)(e.ErrorNumber & 0xffff), e.Message, true);
765 return;
767 if (member == null)
768 member = this.ResolveOtherKindOfCall(args, argIRs, constructor, brackets);
769 if (member == null) return; //Already complained about it, if applicable. Do runtime lookup.
770 if (!this.Accessible(false)){
771 this.member = null;
772 return;
774 WarnIfObsolete();
775 if (member is MethodBase){
776 if (CustomAttribute.IsDefined(member, typeof(JSFunctionAttribute), false) && !(this.defaultMember is PropertyInfo)){
777 int hidden = 0;
778 Object[] attrs = CustomAttribute.GetCustomAttributes(member, typeof(JSFunctionAttribute), false);
779 JSFunctionAttributeEnum attr = ((JSFunctionAttribute)attrs[0]).attributeValue;
780 if ((constructor && !(member is ConstructorInfo)) || (attr & JSFunctionAttributeEnum.HasArguments) != 0){
781 //Can only happen when doing an Eval from slow mode code
782 //Cannot call such methods directly, so bind to the associated field instead
783 this.member = LateBinding.SelectMember(this.members);
784 this.defaultMember = null;
785 return;
787 if ((attr & JSFunctionAttributeEnum.HasThisObject) != 0)
788 hidden = 1;
789 if ((attr & JSFunctionAttributeEnum.HasEngine) != 0)
790 hidden += 1;
791 if (!Binding.CheckParameters(((MethodBase)member).GetParameters(), argIRs, args, this.context, hidden, true, this.isFullyResolved)){
792 this.member = null;
793 return;
795 }else if (constructor && member is JSFieldMethod){
796 //Do a late bound call so that the function as constructor semantics work out
797 this.member = LateBinding.SelectMember(this.members);
798 return;
799 }else if (constructor && member is ConstructorInfo && !(member is JSConstructor) && Typeob.Delegate.IsAssignableFrom(member.DeclaringType)){
800 this.context.HandleError(JSError.DelegatesShouldNotBeExplicitlyConstructed);
801 this.member = null;
802 return;
803 }else
804 if (!Binding.CheckParameters(((MethodBase)member).GetParameters(), argIRs, args, this.context, 0, false, this.isFullyResolved)){
805 this.member = null;
806 return;
809 return;
812 internal override Object ResolveCustomAttribute(ASTList args, IReflect[] argIRs, AST target){
813 try{
814 this.ResolveCall(args, argIRs, true, false);
815 }catch(AmbiguousMatchException){
816 this.context.HandleError(JSError.AmbiguousConstructorCall);
817 return null;
819 JSConstructor jscons = this.member as JSConstructor;
820 if (jscons != null){
821 ClassScope csc = jscons.GetClassScope();
822 if (csc.owner.IsCustomAttribute()) return csc;
823 }else{
824 ConstructorInfo cons = this.member as ConstructorInfo;
825 if (cons != null){
826 Type attrType = cons.DeclaringType;
827 if (Typeob.Attribute.IsAssignableFrom(attrType)){
828 Object[] usageAttrs = CustomAttribute.GetCustomAttributes(attrType, typeof(AttributeUsageAttribute), false);
829 if (usageAttrs.Length > 0) return attrType;
833 this.context.HandleError(JSError.InvalidCustomAttributeClassOrCtor);
834 return null;
837 internal void ResolveLHValue(){
838 MemberInfo member = this.member = LateBinding.SelectMember(this.members);
839 if ((member != null && !this.Accessible(true)) || (this.member == null && this.members.Length > 0)){
840 this.context.HandleError(JSError.AssignmentToReadOnly, this.isFullyResolved);
841 this.member = null; //Recover by going late bound. The runtime routine will fail silently
842 this.members = new MemberInfo[0];
843 return;
845 if (member is JSPrototypeField){ //Go late bound
846 this.member = null;
847 this.members = new MemberInfo[0];
848 return;
850 this.WarnIfNotFullyResolved();
851 this.WarnIfObsolete();
852 return;
855 private MemberInfo ResolveOtherKindOfCall(ASTList argList, IReflect[] argIRs, bool constructor, bool brackets){
856 //There is no method or constructor corresponding to this binding. But there is something else.
857 MemberInfo member = this.member = LateBinding.SelectMember(this.members); //Choose something
859 //If the chosen member is a read-only property on the global object of type Type, replace it with the type.
860 if (member is PropertyInfo && !(member is JSProperty) && member.DeclaringType == Typeob.GlobalObject){
861 PropertyInfo prop = (PropertyInfo)member;
862 Type ptype = prop.PropertyType;
863 if (ptype == Typeob.Type)
864 member = (Type)prop.GetValue(null, null);
865 else if (constructor && brackets){ //Map properties returning fast mode constructor functions to types
866 MethodInfo meth = ptype.GetMethod("CreateInstance", BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
867 if (meth != null){
868 Type rtype = meth.ReturnType;
869 if (rtype == Typeob.BooleanObject)
870 member = Typeob.Boolean;
871 else if (rtype == Typeob.StringObject)
872 member = Typeob.String;
873 else
874 member = rtype;
879 //Check for casts to type expressions, i.e. int[](x)
880 CallableExpression ce = this as CallableExpression;
881 if (ce != null){
882 ConstantWrapper cw = ce.expression as ConstantWrapper;
883 if (cw != null && cw.InferType(null) is Type)
884 member = new JSGlobalField(null, null, cw.value, FieldAttributes.Literal|FieldAttributes.Public);
887 //If the chosen member is a literal field containing a class/function or a nested type, we replace members and try again.
888 if (member is Type){
889 if (constructor){
890 if (brackets){
891 this.isArrayConstructor = true;
892 this.defaultMember = member;
893 this.defaultMemberReturnIR = new TypedArray((Type)member, argIRs.Length);
894 for (int i = 0, n = argIRs.Length; i < n; i++){
895 if (argIRs[i] != Typeob.Object && !Convert.IsPrimitiveNumericType(argIRs[i])){
896 argList[i].context.HandleError(JSError.TypeMismatch, this.isFullyResolved);
897 break;
900 return this.member = member;
901 }else{
902 ConstructorInfo[] constructors = ((Type)member).GetConstructors(BindingFlags.Instance|BindingFlags.Public);
903 if (constructors == null || constructors.Length == 0){
904 this.context.HandleError(JSError.NoConstructor);
905 this.member = null;
906 return null;
908 this.members = constructors;
909 this.ResolveCall(argList, argIRs, true, brackets);
910 return this.member;
912 }else{
913 if (!brackets && argIRs.Length == 1){
914 //Dealing with a type cast
915 return member;
917 this.context.HandleError(JSError.InvalidCall);
918 return this.member = null;
921 if (member is JSPrototypeField)
922 //Have to go late-bound
923 return this.member = null;
924 if (member is FieldInfo && ((FieldInfo)member).IsLiteral){
925 if (!this.AccessibleField(false)) return this.member = null;
926 Object val = member is JSVariableField ? ((JSVariableField)member).value : TypeReferences.GetConstantValue((FieldInfo)member);
927 if ((val is ClassScope || val is Type)){
928 if (constructor){
929 if (brackets){
930 this.isArrayConstructor = true;
931 this.defaultMember = member;
932 this.defaultMemberReturnIR = new TypedArray((val is ClassScope ? (IReflect)val : (IReflect)val), argIRs.Length);
933 for (int i = 0, n = argIRs.Length; i < n; i++){
934 if (argIRs[i] != Typeob.Object && !Convert.IsPrimitiveNumericType(argIRs[i])){
935 argList[i].context.HandleError(JSError.TypeMismatch, this.isFullyResolved);
936 break;
939 return this.member = member;
940 }else{
941 if (val is ClassScope && !((ClassScope)val).owner.isStatic){
942 ConstantWrapper cw = null;
943 if (this is Member && (cw = ((Member)this).rootObject as ConstantWrapper) != null && !(cw.Evaluate() is Namespace)){
944 ((Member)this).rootObject.context.HandleError(JSError.NeedInstance);
945 return null;
948 this.members = val is ClassScope ? ((ClassScope)val).constructors : ((Type)val).GetConstructors(BindingFlags.Instance|BindingFlags.Public);
949 if (this.members == null || this.members.Length == 0){
950 this.context.HandleError(JSError.NoConstructor);
951 this.member = null;
952 return null;
954 this.ResolveCall(argList, argIRs, true, brackets);
955 return this.member;
957 }else{
958 if (!brackets && argIRs.Length == 1){
959 Type ty = val as Type;
960 return this.member = (ty != null ? ty : member);
962 this.context.HandleError(JSError.InvalidCall);
963 return this.member = null;
966 if (val is TypedArray){
967 if (!constructor){ //Casting a value to an array type
968 if (argIRs.Length != 1 || brackets) goto ReportError;
969 return this.member = member;
971 if (!brackets) goto ReportError; //new T(...) where T is an array type.
972 if (argIRs.Length == 0) goto ReportError; //new T[] where T is an array type.
973 this.isArrayConstructor = true;
974 this.defaultMember = member;
975 this.defaultMemberReturnIR = new TypedArray((IReflect)val, argIRs.Length);
976 for (int i = 0, n = argIRs.Length; i < n; i++){
977 if (argIRs[i] != Typeob.Object && !Convert.IsPrimitiveNumericType(argIRs[i])){
978 argList[i].context.HandleError(JSError.TypeMismatch, this.isFullyResolved);
979 break;
982 return this.member = member;
984 if (val is FunctionObject){
985 FunctionObject func = (FunctionObject)val;
986 if (!func.isExpandoMethod && !func.Must_save_stack_locals && (func.own_scope.ProvidesOuterScopeLocals == null || func.own_scope.ProvidesOuterScopeLocals.count == 0))
987 return this.member = ((JSVariableField)this.member).GetAsMethod(func.own_scope);
988 return this.member; //Have to call via the field so that the stack frame is set up correctly
992 //Check the type of this binding for more information
993 IReflect ir = this.InferType(null);
994 Type t = ir as Type;
995 if (!brackets && ((t != null && Typeob.ScriptFunction.IsAssignableFrom(t)) || ir is ScriptFunction)){
996 this.defaultMember = member;
997 if (t == null){
998 this.defaultMemberReturnIR = Globals.TypeRefs.ToReferenceContext(ir.GetType()); //The appropriate subtype of ScriptFunction
999 this.member = this.defaultMemberReturnIR.GetMethod(constructor ? "CreateInstance" : "Invoke",
1000 BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.Instance);
1001 if (this.member == null){
1002 this.defaultMemberReturnIR = Typeob.ScriptFunction;
1003 this.member = this.defaultMemberReturnIR.GetMethod(constructor ? "CreateInstance" : "Invoke",
1004 BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.Instance);
1006 return this.member;
1007 }else{
1008 // We have a script function but it might not be an "expando" function.
1009 if (constructor && this.members.Length != 0 && this.members[0] is JSFieldMethod){
1010 JSFieldMethod fieldmethod = (JSFieldMethod)this.members[0];
1011 fieldmethod.func.PartiallyEvaluate();
1012 if (!fieldmethod.func.isExpandoMethod)
1013 this.context.HandleError(JSError.NotAnExpandoFunction, this.isFullyResolved);
1015 this.defaultMemberReturnIR = t;
1016 return this.member = t.GetMethod(constructor ? "CreateInstance" : "Invoke",
1017 BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.Instance);
1020 if (ir == Typeob.Type){ //Type cast to type only known at runtime
1021 //Have to go late-bound
1022 this.member = null;
1023 return null;
1025 if (ir == Typeob.Object || (ir is ScriptObject && brackets && !(ir is ClassScope)))
1026 //The result of evaluating this binding could be a callable/constructable thing or a thing with a default indexed property.
1027 //Or it could not, but we don't know enough at compile time to moan about it.
1028 return member;
1030 //Perhaps this is an array element access
1031 if (ir is TypedArray || (ir is Type && ((Type)ir).IsArray)){
1032 int n = argIRs.Length;
1033 int m = ir is TypedArray ? ((TypedArray)ir).rank : ((Type)ir).GetArrayRank();
1034 if (n != m)
1035 this.context.HandleError(JSError.IncorrectNumberOfIndices, this.isFullyResolved);
1036 else{
1037 for (int i = 0; i < m; i++){
1038 if (argIRs[i] != Typeob.Object && (!Convert.IsPrimitiveNumericType(argIRs[i]) || Convert.IsBadIndex(argList[i]))){
1039 argList[i].context.HandleError(JSError.TypeMismatch, this.isFullyResolved);
1040 break;
1044 if (constructor){
1045 if (!brackets) goto ReportError;
1046 //dealing with new Arr[...]. Give an error if the array element type is not Object, Type, or ScriptFunction
1047 IReflect elemIR = ir is TypedArray ? ((TypedArray)ir).elementType : ((Type)ir).GetElementType();
1048 if (ir != Typeob.Object && !(ir is ClassScope) &&
1049 !(ir is Type && !Typeob.Type.IsAssignableFrom((Type)ir) && !Typeob.ScriptFunction.IsAssignableFrom((Type)ir)))
1050 goto ReportError;
1052 this.isArrayElementAccess = true;
1053 this.defaultMember = member;
1054 this.defaultMemberReturnIR = ir;
1055 return null; //Delay looking up the method to call until code gen time.
1058 //Perhaps The result of evaluating this binding is an object that has a default indexed property/method that can be called
1059 if (constructor) goto ReportError; //new binding(....) does not make sense for a default indexed property or method
1061 //Check for a default indexed property or default method
1062 if (brackets && ir == Typeob.String && (this.argIRs.Length != 1 || !Convert.IsPrimitiveNumericType(argIRs[0])))
1063 ir = Typeob.StringObject;
1064 MemberInfo[] defaultMembers = brackets || !(ir is ScriptObject) ? JSBinder.GetDefaultMembers(ir) : null;
1065 if (defaultMembers != null && defaultMembers.Length > 0){
1066 try{
1067 this.defaultMember = member;
1068 this.defaultMemberReturnIR = ir;
1069 return this.member = JSBinder.SelectMethod(this.members = defaultMembers, argIRs); //Returns property getters as well
1070 }catch(AmbiguousMatchException){
1071 this.context.HandleError(JSError.AmbiguousMatch, this.isFullyResolved);
1072 return this.member = null;
1076 //Perhaps this is calling a delegate
1077 if (!brackets && ir is Type && Typeob.Delegate.IsAssignableFrom((Type)ir)){
1078 this.defaultMember = member;
1079 this.defaultMemberReturnIR = ir;
1080 return this.member = ((Type)ir).GetMethod("Invoke");
1083 ReportError:
1084 //We now know enough to say that this binding really is not callable/constructable. Say so.
1085 if (constructor)
1086 this.context.HandleError(JSError.NeedType, this.isFullyResolved);
1087 else if (brackets)
1088 this.context.HandleError(JSError.NotIndexable, this.isFullyResolved);
1089 else
1090 this.context.HandleError(JSError.FunctionExpected, this.isFullyResolved);
1091 return this.member = null;
1094 protected void ResolveRHValue(){
1095 MemberInfo member = this.member = LateBinding.SelectMember(this.members);
1096 JSLocalField lfield = this.member as JSLocalField;
1097 if (lfield != null){
1098 FunctionObject funcOb = lfield.value as FunctionObject;
1099 if (funcOb != null){
1100 FunctionScope enclosingScope = funcOb.enclosing_scope as FunctionScope;
1101 if (enclosingScope != null) enclosingScope.closuresMightEscape = true;
1104 if (member is JSPrototypeField){ //Have to go late bound
1105 this.member = null;
1106 return;
1108 if (!this.Accessible(false)){
1109 this.member = null;
1110 return;
1112 WarnIfObsolete();
1113 this.WarnIfNotFullyResolved();
1116 internal override void SetPartialValue(AST partial_value){
1117 Binding.AssignmentCompatible(this.InferType(null), partial_value, partial_value.InferType(null), this.isFullyResolved);
1120 internal void SetPartialValue(ASTList argList, IReflect[] argIRs, AST partial_value, bool inBrackets){
1121 if (this.members == null || this.members.Length == 0){
1122 this.HandleNoSuchMemberError();
1123 this.isAssignmentToDefaultIndexedProperty = true;
1124 return; //Have to do a runtime lookup
1127 this.PartiallyEvaluate(); //The rhside value of the binding delivers the object with the default indexed property we are assigning to
1128 IReflect ir = this.InferType(null);
1129 this.isAssignmentToDefaultIndexedProperty = true;
1130 if (ir == Typeob.Object){
1131 JSVariableField jsvf = this.member as JSVariableField;
1132 if (jsvf == null || !jsvf.IsLiteral || !(jsvf.value is ClassScope))
1133 return; //Not enough is known at compile time to give an error
1134 ir = Typeob.Type;
1135 goto giveError;
1138 //Might be an assignment to an array element
1139 if ((ir is TypedArray || (ir is Type && ((Type)ir).IsArray))){
1140 bool gaveAnError = false;
1141 //Check dimension
1142 int n = argIRs.Length;
1143 int m = ir is TypedArray ? ((TypedArray)ir).rank : ((Type)ir).GetArrayRank();
1144 if (n != m){
1145 this.context.HandleError(JSError.IncorrectNumberOfIndices, this.isFullyResolved);
1146 gaveAnError = true;
1148 //Check type of indices
1149 for (int i = 0; i < m; i++){
1150 if (!gaveAnError && i < n && argIRs[i] != Typeob.Object &&
1151 (!Convert.IsPrimitiveNumericType(argIRs[i]) || Convert.IsBadIndex(argList[i]))){
1152 argList[i].context.HandleError(JSError.TypeMismatch, this.isFullyResolved);
1153 gaveAnError = true;
1156 this.isArrayElementAccess = true;
1157 this.isAssignmentToDefaultIndexedProperty = false;
1158 this.defaultMember = member;
1159 this.defaultMemberReturnIR = ir;
1161 //Check type of rhside
1162 IReflect elemIR = ir is TypedArray ? ((TypedArray)ir).elementType : ((Type)ir).GetElementType();
1163 Binding.AssignmentCompatible(elemIR, partial_value, partial_value.InferType(null), this.isFullyResolved);
1164 return;
1167 //Might be an assignment to a default indexed property
1168 MemberInfo[] defaultMembers = JSBinder.GetDefaultMembers(ir);
1169 if (defaultMembers != null && defaultMembers.Length > 0 && this.member != null){
1170 try{
1171 PropertyInfo prop = JSBinder.SelectProperty(defaultMembers, argIRs);
1172 if (prop == null){
1173 this.context.HandleError(JSError.NotIndexable, Convert.ToTypeName(ir));
1174 return;
1176 if (JSProperty.GetSetMethod(prop, true) == null){
1177 if (ir == Typeob.String)
1178 this.context.HandleError(JSError.UselessAssignment);
1179 else
1180 this.context.HandleError(JSError.AssignmentToReadOnly, this.isFullyResolved&&this.Engine.doFast);
1181 return;
1183 if (!Binding.CheckParameters(prop.GetIndexParameters(), argIRs, argList, this.context, 0, false, true)){
1184 return;
1186 this.defaultMember = this.member;
1187 this.defaultMemberReturnIR = ir;
1188 this.members = defaultMembers;
1189 this.member = prop;
1190 }catch(AmbiguousMatchException){
1191 this.context.HandleError(JSError.AmbiguousMatch, this.isFullyResolved);
1192 this.member = null;
1194 return;
1197 giveError:
1198 this.member = null;
1199 if (!inBrackets)
1200 this.context.HandleError(JSError.IllegalAssignment);
1201 else
1202 this.context.HandleError(JSError.NotIndexable, Convert.ToTypeName(ir));
1205 internal override void SetValue(Object value){
1206 MemberInfo member = this.member;
1207 Object ob = this.GetObject();
1208 if (member is FieldInfo){
1209 FieldInfo field = (FieldInfo)member;
1210 if (field.IsLiteral || field.IsInitOnly) return;
1211 if (!(field is JSField) || field is JSWrappedField)
1212 value = Convert.CoerceT(value, field.FieldType, false);
1213 field.SetValue(ob, value, BindingFlags.SuppressChangeType, null, null);
1214 return;
1216 if (member is PropertyInfo){
1217 PropertyInfo prop = (PropertyInfo)member;
1218 if (ob is ClassScope && !(prop is JSProperty)){
1219 JSProperty.SetValue(prop, ((WithObject)((ClassScope)ob).GetParent()).contained_object, value, null);
1220 return;
1222 if (!(prop is JSProperty))
1223 value = Convert.CoerceT(value, prop.PropertyType, false);
1224 JSProperty.SetValue(prop, ob, value, null);
1225 return;
1227 if (this.members == null || this.members.Length == 0){
1228 this.EvaluateAsLateBinding().SetValue(value);
1229 return;
1231 //The name has been bound to something and that something is not a valid assignment target.
1232 throw new JScriptException(JSError.IllegalAssignment);
1235 internal override void TranslateToIL(ILGenerator il, Type rtype){
1236 this.TranslateToIL(il, rtype, false, false);
1239 internal void TranslateToIL(ILGenerator il, Type rtype, bool calledFromDelete){
1240 this.TranslateToIL(il, rtype, false, false, calledFromDelete);
1243 private void TranslateToIL(ILGenerator il, Type rtype, bool preSet, bool preSetPlusGet){
1244 this.TranslateToIL(il, rtype, preSet, preSetPlusGet, false);
1247 private void TranslateToIL(ILGenerator il, Type rtype, bool preSet, bool preSetPlusGet, bool calledFromDelete){
1248 if (this.member is FieldInfo){
1249 FieldInfo field = (FieldInfo)this.member;
1250 bool isStatic = field.IsStatic || field.IsLiteral;
1251 if (field.IsLiteral && field is JSMemberField){
1252 Object val = ((JSMemberField)field).value;
1253 FunctionObject func = val as FunctionObject;
1254 isStatic = func == null || !func.isExpandoMethod;
1256 if (!isStatic || field is JSClosureField){
1257 this.TranslateToILObject(il, field.DeclaringType, true);
1258 if (preSetPlusGet)
1259 il.Emit(OpCodes.Dup);
1260 isStatic = false;
1262 if (!preSet){
1263 Object tok = field is JSField ? ((JSField)field).GetMetaData() : field is JSFieldInfo ? ((JSFieldInfo)field).field : field;
1264 if (tok is FieldInfo && !((FieldInfo)tok).IsLiteral)
1265 il.Emit(isStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, (FieldInfo)tok);
1266 else if (tok is LocalBuilder)
1267 il.Emit(OpCodes.Ldloc, (LocalBuilder)tok);
1268 else if (field.IsLiteral){
1269 (new ConstantWrapper(TypeReferences.GetConstantValue(field), this.context)).TranslateToIL(il, rtype);
1270 return;
1271 }else
1272 Convert.EmitLdarg(il, (short)tok);
1273 Convert.Emit(this, il, field.FieldType, rtype);
1275 return;
1277 if (this.member is PropertyInfo){
1278 PropertyInfo prop = (PropertyInfo)this.member;
1279 MethodInfo meth = preSet ? JSProperty.GetSetMethod(prop, true) : JSProperty.GetGetMethod(prop, true);
1280 if (meth == null){
1281 if (preSet) return;
1282 if (this is Lookup){
1283 il.Emit(OpCodes.Ldc_I4, (int)JSError.WriteOnlyProperty);
1284 il.Emit(OpCodes.Newobj, CompilerGlobals.scriptExceptionConstructor);
1285 il.Emit(OpCodes.Throw);
1286 }else
1287 il.Emit(OpCodes.Ldnull);
1288 return;
1290 bool isStatic = meth.IsStatic && !(meth is JSClosureMethod);
1291 if (!isStatic){
1292 Type obType = meth.DeclaringType;
1293 if (obType == Typeob.StringObject && meth.Name.Equals("get_length")){
1294 this.TranslateToILObject(il, Typeob.String, false);
1295 meth = CompilerGlobals.stringLengthMethod;
1296 }else
1297 this.TranslateToILObject(il, obType, true);
1299 if (!preSet){
1300 Debug.Assert(meth.GetParameters().Length == 0);
1301 meth = this.GetMethodInfoMetadata(meth);
1302 if (isStatic){
1303 il.Emit(OpCodes.Call, meth);
1304 }else{
1305 if (preSetPlusGet)
1306 il.Emit(OpCodes.Dup);
1307 if (!this.isNonVirtual && meth.IsVirtual && !meth.IsFinal && (!meth.ReflectedType.IsSealed || !meth.ReflectedType.IsValueType))
1308 il.Emit(OpCodes.Callvirt, meth);
1309 else
1310 il.Emit(OpCodes.Call, meth);
1312 Convert.Emit(this, il, meth.ReturnType, rtype);
1314 return;
1316 if (this.member is MethodInfo){
1317 MethodInfo meth = this.GetMethodInfoMetadata((MethodInfo)this.member);
1318 if (Typeob.Delegate.IsAssignableFrom(rtype)){
1319 if (!meth.IsStatic){
1320 Type obType = meth.DeclaringType;
1321 this.TranslateToILObject(il, obType, false);
1322 if (obType.IsValueType)
1323 il.Emit(OpCodes.Box, obType);
1324 }else
1325 il.Emit(OpCodes.Ldnull);
1326 if (meth.IsVirtual && !meth.IsFinal && (!meth.ReflectedType.IsSealed || !meth.ReflectedType.IsValueType)){
1327 il.Emit(OpCodes.Dup);
1328 il.Emit(OpCodes.Ldvirtftn, meth);
1329 }else
1330 il.Emit(OpCodes.Ldftn, meth);
1331 ConstructorInfo cons = rtype.GetConstructor(new Type[]{Typeob.Object, Typeob.UIntPtr});
1332 if (cons == null) cons = rtype.GetConstructor(new Type[]{Typeob.Object, Typeob.IntPtr});
1333 il.Emit(OpCodes.Newobj, cons);
1334 return;
1336 //ResolveRHValue will never set this.member to a MethodInfo. The above case only happens
1337 //because IsCompatibleWithDelegate sets this.member to the method that matches the delegate type.
1338 if (member is JSExpandoIndexerMethod){
1339 //Need to put the expando class instance on the stack as the this object in expressions such as exInstance["foo"]90
1340 MemberInfo mem = this.member;
1341 this.member = this.defaultMember;
1342 this.TranslateToIL(il, Typeob.Object);
1343 this.member = mem;
1344 return;
1346 il.Emit(OpCodes.Ldnull); //get something on the stack, in case we DO get here
1347 Convert.Emit(this, il, Typeob.Object, rtype);
1348 return;
1350 Object done = null;
1351 if (this is Lookup)
1352 ((Lookup)this).TranslateToLateBinding(il);
1353 else{
1354 if (!this.isFullyResolved && !preSet && !preSetPlusGet)
1355 done = this.TranslateToSpeculativeEarlyBindings(il, rtype, false);
1356 ((Member)this).TranslateToLateBinding(il, done != null);
1357 if (!this.isFullyResolved && preSetPlusGet)
1358 done = this.TranslateToSpeculativeEarlyBindings(il, rtype, true);
1360 if (preSetPlusGet)
1361 il.Emit(OpCodes.Dup);
1362 if (!preSet){
1363 if (this is Lookup && !calledFromDelete)
1364 il.Emit(OpCodes.Call, CompilerGlobals.getValue2Method);
1365 else
1366 il.Emit(OpCodes.Call, CompilerGlobals.getNonMissingValueMethod);
1367 Convert.Emit(this, il, Typeob.Object, rtype);
1368 if (done != null)
1369 il.MarkLabel((Label)done);
1373 internal override void TranslateToILCall(ILGenerator il, Type rtype, ASTList argList, bool construct, bool brackets){
1374 MemberInfo member = this.member;
1375 if (this.defaultMember != null){
1376 if (this.isArrayConstructor){
1377 TypedArray tArr = (TypedArray)this.defaultMemberReturnIR;
1378 Type eType = Convert.ToType(tArr.elementType);
1379 Debug.Assert(tArr.rank == argList.count);
1380 int r = tArr.rank;
1381 if (r == 1){
1382 argList[0].TranslateToIL(il, Typeob.Int32);
1383 il.Emit(OpCodes.Newarr, eType);
1384 }else{
1385 Type aType = tArr.ToType();
1386 Type[] dTypes = new Type[r];
1387 for (int i = 0; i < r; i++) dTypes[i] = Typeob.Int32;
1388 for (int i = 0, n = argList.count; i < n; i++)
1389 argList[i].TranslateToIL(il, Typeob.Int32);
1390 TypeBuilder eTypeB = eType as TypeBuilder;
1391 if (eTypeB != null){
1392 MethodInfo cons = ((ModuleBuilder)aType.Module).GetArrayMethod(aType, ".ctor", CallingConventions.HasThis, Typeob.Void, dTypes);
1393 il.Emit(OpCodes.Newobj, cons);
1394 }else{
1395 ConstructorInfo cons = aType.GetConstructor(dTypes);
1396 il.Emit(OpCodes.Newobj, cons);
1399 Convert.Emit(this, il, tArr.ToType(), rtype);
1400 return;
1402 this.member = this.defaultMember;
1403 IReflect defIR = this.defaultMemberReturnIR;
1404 Type defType = defIR is Type ? (Type)defIR : Convert.ToType(defIR);
1405 this.TranslateToIL(il, defType);
1406 if (this.isArrayElementAccess){
1407 Debug.Assert(defType.IsArray);
1408 for (int i = 0, m = argList.count; i < m; i++)
1409 argList[i].TranslateToIL(il, Typeob.Int32);
1410 Type etype = defType.GetElementType();
1411 int n = defType.GetArrayRank();
1412 if (n == 1){
1413 Binding.TranslateToLdelem(il, etype);
1414 }else{
1415 Type[] indexTypes = new Type[n];
1416 for (int i = 0; i < n; i++) indexTypes[i] = Typeob.Int32;
1417 MethodInfo getter = compilerGlobals.module.GetArrayMethod(defType, "Get", CallingConventions.HasThis, etype, indexTypes);
1418 il.Emit(OpCodes.Call, getter);
1420 Convert.Emit(this, il, etype, rtype);
1421 return;
1423 this.member = member;
1425 if (member is MethodInfo){
1426 MethodInfo meth = (MethodInfo)member;
1427 Type dt = meth.DeclaringType;
1428 Type rt = meth.ReflectedType;
1429 ParameterInfo[] pars = meth.GetParameters();
1430 bool isStatic = meth.IsStatic;
1431 if (!isStatic && this.defaultMember == null)
1432 this.TranslateToILObject(il, dt, true);
1433 if (meth is JSClosureMethod)
1434 this.TranslateToILObject(il, dt, false);
1435 ConstantWrapper missing = null;
1436 int offset = 0;
1437 if (meth is JSFieldMethod || CustomAttribute.IsDefined(meth, typeof(JSFunctionAttribute), false)){
1438 offset = this.PlaceValuesForHiddenParametersOnStack(il, meth, pars);
1439 missing = Binding.JScriptMissingCW;
1440 }else
1441 missing = Binding.ReflectionMissingCW;
1442 if (argList.count == 1 && missing == Binding.JScriptMissingCW && this.defaultMember is PropertyInfo){
1443 //Dealing with the CreateInstance method of a constructor function
1444 Debug.Assert(meth.Name == "CreateInstance" || meth.Name == "Invoke");
1445 il.Emit(OpCodes.Ldc_I4_1);
1446 il.Emit(OpCodes.Newarr, Typeob.Object);
1447 il.Emit(OpCodes.Dup);
1448 il.Emit(OpCodes.Ldc_I4_0);
1449 argList[0].TranslateToIL(il, Typeob.Object);
1450 il.Emit(OpCodes.Stelem_Ref);
1451 }else
1452 Binding.PlaceArgumentsOnStack(il, pars, argList, offset, 0, missing);
1453 meth = this.GetMethodInfoMetadata(meth);
1454 if (!this.isNonVirtual && meth.IsVirtual && !meth.IsFinal && (!rt.IsSealed || !rt.IsValueType))
1455 il.Emit(OpCodes.Callvirt, meth);
1456 else
1457 il.Emit(OpCodes.Call, meth);
1458 Convert.Emit(this, il, meth.ReturnType, rtype);
1459 return;
1461 if (member is ConstructorInfo){
1462 Debug.Assert(construct);
1463 ConstructorInfo cons = (ConstructorInfo)member;
1464 ParameterInfo[] pars = cons.GetParameters();
1465 bool instanceNestedClassConstructor = false;
1466 if (CustomAttribute.IsDefined(cons, typeof(JSFunctionAttribute), false)){
1467 Object[] attrs = CustomAttribute.GetCustomAttributes(cons, typeof(JSFunctionAttribute), false);
1468 instanceNestedClassConstructor = (((JSFunctionAttribute)attrs[0]).attributeValue & JSFunctionAttributeEnum.IsInstanceNestedClassConstructor) != 0;
1470 if (instanceNestedClassConstructor){
1471 Binding.PlaceArgumentsOnStack(il, pars, argList, 0, 1, Binding.ReflectionMissingCW);
1472 this.TranslateToILObject(il, pars[pars.Length-1].ParameterType, false);
1473 }else
1474 Binding.PlaceArgumentsOnStack(il, pars, argList, 0, 0, Binding.ReflectionMissingCW);
1475 Type outerClass = null;
1476 if (member is JSConstructor && (outerClass = ((JSConstructor)member).OuterClassType()) != null)
1477 this.TranslateToILObject(il, outerClass, false);
1478 bool needEngine = false;
1479 Type t = cons.DeclaringType;
1480 if (cons is JSConstructor){
1481 cons = ((JSConstructor)cons).GetConstructorInfo(compilerGlobals);
1482 needEngine = true;
1483 }else
1484 needEngine = Typeob.INeedEngine.IsAssignableFrom(t);
1485 il.Emit(OpCodes.Newobj, cons);
1486 if (needEngine){
1487 il.Emit(OpCodes.Dup);
1488 this.EmitILToLoadEngine(il);
1489 il.Emit(OpCodes.Callvirt, CompilerGlobals.setEngineMethod);
1491 Convert.Emit(this, il, t, rtype);
1492 return;
1494 Type mt = member as Type;
1495 if (mt != null){
1496 Debug.Assert(!construct && !brackets);
1497 Debug.Assert(argList.count == 1);
1498 AST arg0 = argList[0];
1499 if (arg0 is NullLiteral){ //Skip the double conversion path below that involves runtime helper
1500 arg0.TranslateToIL(il, mt);
1501 Convert.Emit(this, il, mt, rtype);
1502 return;
1504 IReflect arg0ir = arg0.InferType(null);
1505 if (arg0ir == Typeob.ScriptFunction && Typeob.Delegate.IsAssignableFrom(mt))
1506 arg0.TranslateToIL(il, mt);
1507 else{
1508 Type argType = Convert.ToType(arg0ir);
1509 arg0.TranslateToIL(il, argType);
1510 Convert.Emit(this, il, argType, mt, true);
1512 Convert.Emit(this, il, mt, rtype);
1513 return;
1515 if (member is FieldInfo && ((FieldInfo)member).IsLiteral){
1516 Object val = member is JSVariableField ? ((JSVariableField)member).value : TypeReferences.GetConstantValue((FieldInfo)member);
1517 if (val is Type || val is ClassScope || val is TypedArray){
1518 Debug.Assert(argList.count == 1);
1519 AST arg0 = argList[0];
1520 if (arg0 is NullLiteral){
1521 il.Emit(OpCodes.Ldnull);
1522 return;
1524 ClassScope csc = val as ClassScope;
1525 if (csc != null){
1526 EnumDeclaration ed = csc.owner as EnumDeclaration;
1527 if (ed != null)
1528 val = ed.baseType.ToType();
1530 Type argType = Convert.ToType(arg0.InferType(null));
1531 arg0.TranslateToIL(il, argType);
1532 Type t = val is Type ? (Type)val : val is ClassScope ? Convert.ToType((ClassScope)val) : ((TypedArray)val).ToType();
1533 Convert.Emit(this, il, argType, t, true);
1534 if (!rtype.IsEnum)
1535 Convert.Emit(this, il, t, rtype);
1536 return;
1539 LocalBuilder loc = null;
1540 for (int i = 0, n = argList.count; i < n; i++){
1541 if (argList[i] is AddressOf){
1542 loc = il.DeclareLocal(Typeob.ArrayOfObject);
1543 break;
1546 Object done = null;
1547 if (member == null && (this.members == null || this.members.Length == 0)){
1548 if (this is Lookup)
1549 ((Lookup)this).TranslateToLateBinding(il);
1550 else{
1551 done = this.TranslateToSpeculativeEarlyBoundCalls(il, rtype, argList, construct, brackets);
1552 ((Member)this).TranslateToLateBinding(il, done != null);
1554 argList.TranslateToIL(il, Typeob.ArrayOfObject);
1555 if (loc != null){
1556 il.Emit(OpCodes.Dup);
1557 il.Emit(OpCodes.Stloc, loc);
1559 if (construct)
1560 il.Emit(OpCodes.Ldc_I4_1);
1561 else
1562 il.Emit(OpCodes.Ldc_I4_0);
1563 if (brackets)
1564 il.Emit(OpCodes.Ldc_I4_1);
1565 else
1566 il.Emit(OpCodes.Ldc_I4_0);
1567 this.EmitILToLoadEngine(il);
1568 il.Emit(OpCodes.Call, CompilerGlobals.callMethod);
1569 Convert.Emit(this, il, Typeob.Object, rtype);
1570 if (loc != null){
1571 for (int i = 0, n = argList.count; i < n; i++){
1572 AddressOf addr = argList[i] as AddressOf;
1573 if (addr != null){
1574 addr.TranslateToILPreSet(il);
1575 il.Emit(OpCodes.Ldloc, loc);
1576 ConstantWrapper.TranslateToILInt(il, i);
1577 il.Emit(OpCodes.Ldelem_Ref);
1578 Convert.Emit(this, il, Typeob.Object, Convert.ToType(addr.InferType(null)));
1579 addr.TranslateToILSet(il, null);
1583 if (done != null)
1584 il.MarkLabel((Label)done);
1585 return;
1587 this.TranslateToILWithDupOfThisOb(il);
1588 argList.TranslateToIL(il, Typeob.ArrayOfObject);
1589 if (loc != null){
1590 il.Emit(OpCodes.Dup);
1591 il.Emit(OpCodes.Stloc, loc);
1593 if (construct)
1594 il.Emit(OpCodes.Ldc_I4_1);
1595 else
1596 il.Emit(OpCodes.Ldc_I4_0);
1597 if (brackets)
1598 il.Emit(OpCodes.Ldc_I4_1);
1599 else
1600 il.Emit(OpCodes.Ldc_I4_0);
1601 this.EmitILToLoadEngine(il);
1602 il.Emit(OpCodes.Call, CompilerGlobals.callValueMethod);
1603 Convert.Emit(this, il, Typeob.Object, rtype);
1604 if (loc != null){
1605 for (int i = 0, n = argList.count; i < n; i++){
1606 AddressOf addr = argList[i] as AddressOf;
1607 if (addr != null){
1608 addr.TranslateToILPreSet(il);
1609 il.Emit(OpCodes.Ldloc, loc);
1610 ConstantWrapper.TranslateToILInt(il, i);
1611 il.Emit(OpCodes.Ldelem_Ref);
1612 Convert.Emit(this, il, Typeob.Object, Convert.ToType(addr.InferType(null)));
1613 addr.TranslateToILSet(il, null);
1619 internal override void TranslateToILDelete(ILGenerator il, Type rtype){
1620 if (this is Lookup)
1621 ((Lookup)this).TranslateToLateBinding(il);
1622 else
1623 ((Member)this).TranslateToLateBinding(il, false);
1624 il.Emit(OpCodes.Call, CompilerGlobals.deleteMethod);
1625 Convert.Emit(this, il, Typeob.Boolean, rtype);
1628 protected abstract void TranslateToILObject(ILGenerator il, Type obtype, bool noValue);
1630 internal override void TranslateToILPreSet(ILGenerator il){
1631 this.TranslateToIL(il, null, true, false);
1634 internal override void TranslateToILPreSet(ILGenerator il, ASTList argList){
1635 if (this.isArrayElementAccess){
1636 this.member = this.defaultMember;
1637 IReflect defIR = this.defaultMemberReturnIR;
1638 Type defType = defIR is Type ? (Type)defIR : Convert.ToType(defIR);
1639 this.TranslateToIL(il, defType);
1640 Debug.Assert(defType.IsArray);
1641 for (int i = 0, m = argList.count; i < m; i++)
1642 argList[i].TranslateToIL(il, Typeob.Int32);
1643 if (defType.GetArrayRank() == 1){
1644 Type etype = defType.GetElementType();
1645 if (etype.IsValueType && !etype.IsPrimitive && !etype.IsEnum)
1646 il.Emit(OpCodes.Ldelema, etype);
1648 return;
1650 Debug.Assert(this.isAssignmentToDefaultIndexedProperty);
1651 if (this.member is PropertyInfo && this.defaultMember != null){ //early bound to default indexed property
1652 PropertyInfo prop = (PropertyInfo)this.member;
1653 this.member = this.defaultMember;
1654 this.TranslateToIL(il, Convert.ToType(this.defaultMemberReturnIR));
1655 this.member = prop;
1656 Binding.PlaceArgumentsOnStack(il, prop.GetIndexParameters(), argList, 0, 0, Binding.ReflectionMissingCW);
1657 return;
1659 base.TranslateToILPreSet(il, argList);
1662 internal override void TranslateToILPreSetPlusGet(ILGenerator il){
1663 this.TranslateToIL(il, Convert.ToType(this.InferType(null)), false, true);
1666 internal override void TranslateToILPreSetPlusGet(ILGenerator il, ASTList argList, bool inBrackets){
1667 if (this.isArrayElementAccess){
1668 this.member = this.defaultMember;
1669 IReflect defIR = this.defaultMemberReturnIR;
1670 Type defType = defIR is Type ? (Type)defIR : Convert.ToType(defIR);
1671 Debug.Assert(defType.IsArray);
1672 this.TranslateToIL(il, defType);
1673 il.Emit(OpCodes.Dup);
1674 int n = defType.GetArrayRank();
1675 LocalBuilder[] iTemp = new LocalBuilder[n];
1676 for (int i = 0, m = argList.count; i < m; i++){
1677 argList[i].TranslateToIL(il, Typeob.Int32);
1678 iTemp[i] = il.DeclareLocal(Typeob.Int32);
1679 il.Emit(OpCodes.Dup);
1680 il.Emit(OpCodes.Stloc, iTemp[i]);
1682 Type etype = defType.GetElementType();
1683 if (n == 1){
1684 Binding.TranslateToLdelem(il, etype);
1685 }else{
1686 Type[] indexTypes = new Type[n];
1687 for (int i = 0; i < n; i++) indexTypes[i] = Typeob.Int32;
1688 MethodInfo getter = defType.GetMethod("Get", indexTypes);
1689 il.Emit(OpCodes.Call, getter);
1691 LocalBuilder eTemp = il.DeclareLocal(etype);
1692 il.Emit(OpCodes.Stloc, eTemp);
1693 for (int i = 0; i < n; i++)
1694 il.Emit(OpCodes.Ldloc, iTemp[i]);
1695 if (n == 1 && etype.IsValueType && !etype.IsPrimitive)
1696 il.Emit(OpCodes.Ldelema, etype);
1697 il.Emit(OpCodes.Ldloc, eTemp);
1698 return;
1700 Debug.Assert(this.isAssignmentToDefaultIndexedProperty);
1701 if (this.member != null){
1702 //Go late bound. It is too much work, for too little gain, to do this early bound
1703 if (this.defaultMember != null){
1704 this.member = this.defaultMember;
1705 this.defaultMember = null;
1708 base.TranslateToILPreSetPlusGet(il, argList, inBrackets);
1711 internal override Object TranslateToILReference(ILGenerator il, Type rtype){
1712 if (this.member is FieldInfo){
1713 FieldInfo field = (FieldInfo)this.member;
1714 Type ftype = field.FieldType;
1715 if (rtype == ftype){
1716 bool isStatic = field.IsStatic;
1717 if (!isStatic)
1718 this.TranslateToILObject(il, field.DeclaringType, true);
1719 Object tok = field is JSField ? ((JSField)field).GetMetaData() : field is JSFieldInfo ? ((JSFieldInfo)field).field : field;
1720 if (tok is FieldInfo)
1721 if (field.IsInitOnly){
1722 LocalBuilder loc = il.DeclareLocal(ftype);
1723 il.Emit(isStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, (FieldInfo)tok);
1724 il.Emit(OpCodes.Stloc, loc);
1725 il.Emit(OpCodes.Ldloca, loc);
1726 }else
1727 il.Emit(isStatic ? OpCodes.Ldsflda : OpCodes.Ldflda, (FieldInfo)tok);
1728 else if (tok is LocalBuilder)
1729 il.Emit(OpCodes.Ldloca, (LocalBuilder)tok);
1730 else
1731 il.Emit(OpCodes.Ldarga, (short)tok);
1732 return null;
1735 return base.TranslateToILReference(il, rtype);
1738 internal override void TranslateToILSet(ILGenerator il, AST rhvalue){
1739 if (this.isArrayElementAccess){
1740 IReflect defIR = this.defaultMemberReturnIR;
1741 Type defType = defIR is Type ? (Type)defIR : Convert.ToType(defIR);
1742 Debug.Assert(defType.IsArray);
1743 int n = defType.GetArrayRank();
1744 Type etype = defType.GetElementType();
1745 if (rhvalue != null)
1746 rhvalue.TranslateToIL(il, etype);
1747 if (n == 1){
1748 Binding.TranslateToStelem(il, etype);
1749 }else{
1750 Type[] indexTypes = new Type[n+1];
1751 for (int i = 0; i < n; i++) indexTypes[i] = Typeob.Int32;
1752 indexTypes[n] = etype;
1753 MethodInfo setter = compilerGlobals.module.GetArrayMethod(defType, "Set", CallingConventions.HasThis, Typeob.Void, indexTypes);
1754 il.Emit(OpCodes.Call, setter);
1756 return;
1758 if (this.isAssignmentToDefaultIndexedProperty){
1759 if (this.member is PropertyInfo && this.defaultMember != null){ //early bound to default indexed property
1760 PropertyInfo prop = (PropertyInfo)this.member;
1761 MethodInfo meth = JSProperty.GetSetMethod(prop, false);
1762 //Guard against trying to assign to properties on the Global object
1763 JSWrappedMethod wmeth = meth as JSWrappedMethod;
1764 if (wmeth == null || !(wmeth.GetWrappedObject() is GlobalObject)){
1765 meth = this.GetMethodInfoMetadata(meth);
1766 if (rhvalue != null)
1767 rhvalue.TranslateToIL(il, prop.PropertyType);
1768 if (meth.IsVirtual && !meth.IsFinal && (!meth.ReflectedType.IsSealed || !meth.ReflectedType.IsValueType))
1769 il.Emit(OpCodes.Callvirt, meth);
1770 else
1771 il.Emit(OpCodes.Call, meth);
1772 return;
1775 base.TranslateToILSet(il, rhvalue);
1776 return;
1778 if (this.member is FieldInfo){
1779 FieldInfo field = (FieldInfo)this.member;
1780 if (rhvalue != null)
1781 rhvalue.TranslateToIL(il, field.FieldType);
1782 if (field.IsLiteral || field.IsInitOnly){
1783 il.Emit(OpCodes.Pop);
1784 return;
1786 Object tok = field is JSField ? ((JSField)field).GetMetaData() : field is JSFieldInfo ? ((JSFieldInfo)field).field : field;
1787 FieldInfo f = tok as FieldInfo;
1788 if (f != null)
1789 il.Emit(f.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, f);
1790 else if (tok is LocalBuilder)
1791 il.Emit(OpCodes.Stloc, (LocalBuilder)tok);
1792 else
1793 il.Emit(OpCodes.Starg, (short)tok);
1794 return;
1796 if (this.member is PropertyInfo){
1797 PropertyInfo prop = (PropertyInfo)this.member;
1798 if (rhvalue != null)
1799 rhvalue.TranslateToIL(il, prop.PropertyType);
1800 MethodInfo meth = JSProperty.GetSetMethod(prop, true);
1801 if (meth == null){
1802 il.Emit(OpCodes.Pop);
1803 return;
1805 meth = this.GetMethodInfoMetadata(meth);
1806 if (meth.IsStatic && !(meth is JSClosureMethod))
1807 il.Emit(OpCodes.Call, meth);
1808 else{
1809 if (!this.isNonVirtual && meth.IsVirtual && !meth.IsFinal && (!meth.ReflectedType.IsSealed || !meth.ReflectedType.IsValueType))
1810 il.Emit(OpCodes.Callvirt, meth);
1811 else
1812 il.Emit(OpCodes.Call, meth);
1814 return;
1816 //do speculative early bound assignments
1817 Object done = this.TranslateToSpeculativeEarlyBoundSet(il, rhvalue);
1818 if (rhvalue != null)
1819 rhvalue.TranslateToIL(il, Typeob.Object);
1820 il.Emit(OpCodes.Call, CompilerGlobals.setValueMethod);
1821 if (done != null)
1822 il.MarkLabel((Label)done);
1825 protected abstract void TranslateToILWithDupOfThisOb(ILGenerator il);
1827 private static void TranslateToLdelem(ILGenerator il, Type etype){
1828 switch(Type.GetTypeCode(etype)){
1829 case TypeCode.SByte:
1830 il.Emit(OpCodes.Ldelem_I1); break;
1831 case TypeCode.Boolean:
1832 case TypeCode.Byte:
1833 il.Emit(OpCodes.Ldelem_U1); break;
1834 case TypeCode.Int16:
1835 il.Emit(OpCodes.Ldelem_I2); break;
1836 case TypeCode.Char:
1837 case TypeCode.UInt16:
1838 il.Emit(OpCodes.Ldelem_U2); break;
1839 case TypeCode.Int32:
1840 il.Emit(OpCodes.Ldelem_I4); break;
1841 case TypeCode.UInt32:
1842 il.Emit(OpCodes.Ldelem_U4); break;
1843 case TypeCode.Int64:
1844 case TypeCode.UInt64:
1845 il.Emit(OpCodes.Ldelem_I8); break;
1846 case TypeCode.Single:
1847 il.Emit(OpCodes.Ldelem_R4); break;
1848 case TypeCode.Double:
1849 il.Emit(OpCodes.Ldelem_R8); break;
1850 case TypeCode.Decimal:
1851 case TypeCode.DateTime:
1852 case TypeCode.String:
1853 case TypeCode.Object:
1854 if (etype.IsValueType){
1855 il.Emit(OpCodes.Ldelema, etype);
1856 il.Emit(OpCodes.Ldobj, etype);
1857 }else
1858 il.Emit(OpCodes.Ldelem_Ref);
1859 break;
1863 private Object TranslateToSpeculativeEarlyBoundSet(ILGenerator il, AST rhvalue){
1864 this.giveErrors = false;
1865 Object done = null;
1866 bool needObject = true;
1867 LocalBuilder objectLocal = null;
1868 LocalBuilder valueLocal = null;
1869 Label next = il.DefineLabel();
1870 MemberInfoList members = this.GetAllKnownInstanceBindingsForThisName();
1871 for (int i = 0, n = members.count; i < n; i++){
1872 MemberInfo member = members[i];
1873 FieldInfo field = null;
1874 MethodInfo setter = null;
1875 PropertyInfo prop = null;
1876 if (member is FieldInfo){
1877 field = (FieldInfo)member;
1878 if (field.IsLiteral || field.IsInitOnly) continue;
1879 }else if (member is PropertyInfo){
1880 prop = (PropertyInfo)member;
1881 if (prop.GetIndexParameters().Length > 0 ||
1882 (setter = JSProperty.GetSetMethod(prop, true)) == null) continue;
1883 }else
1884 continue;
1885 this.member = member;
1886 if (!this.Accessible(true)) continue;
1887 if (needObject){
1888 needObject = false;
1889 if (rhvalue == null){
1890 valueLocal = il.DeclareLocal(Typeob.Object);
1891 il.Emit(OpCodes.Stloc, valueLocal);
1893 il.Emit(OpCodes.Dup);
1894 il.Emit(OpCodes.Ldfld, CompilerGlobals.objectField);
1895 objectLocal = il.DeclareLocal(Typeob.Object);
1896 il.Emit(OpCodes.Stloc, objectLocal);
1897 done = il.DefineLabel();
1899 Type t = member.DeclaringType;
1900 il.Emit(OpCodes.Ldloc, objectLocal);
1901 il.Emit(OpCodes.Isinst, t);
1902 LocalBuilder objectTemp = il.DeclareLocal(t);
1903 il.Emit(OpCodes.Dup);
1904 il.Emit(OpCodes.Stloc, objectTemp);
1905 il.Emit(OpCodes.Brfalse, next);
1906 il.Emit(OpCodes.Ldloc, objectTemp);
1907 if (rhvalue == null)
1908 il.Emit(OpCodes.Ldloc, valueLocal);
1909 if (field != null){
1910 if (rhvalue == null)
1911 Convert.Emit(this, il, Typeob.Object, field.FieldType);
1912 else
1913 rhvalue.TranslateToIL(il, field.FieldType);
1914 if (field is JSField)
1915 il.Emit(OpCodes.Stfld, (FieldInfo)((JSField)field).GetMetaData());
1916 else if (field is JSFieldInfo)
1917 il.Emit(OpCodes.Stfld, ((JSFieldInfo)field).field);
1918 else
1919 il.Emit(OpCodes.Stfld, field);
1920 }else{
1921 if (rhvalue == null)
1922 Convert.Emit(this, il, Typeob.Object, prop.PropertyType);
1923 else
1924 rhvalue.TranslateToIL(il, prop.PropertyType);
1925 setter = this.GetMethodInfoMetadata(setter);
1926 if (setter.IsVirtual && !setter.IsFinal && (!t.IsSealed || !t.IsValueType))
1927 il.Emit(OpCodes.Callvirt, setter);
1928 else
1929 il.Emit(OpCodes.Call, setter);
1931 il.Emit(OpCodes.Pop); //Get rid of the LateBound instance
1932 il.Emit(OpCodes.Br, (Label)done);
1933 il.MarkLabel(next);
1934 next = il.DefineLabel();
1936 if (valueLocal != null)
1937 il.Emit(OpCodes.Ldloc, valueLocal);
1938 this.member = null;
1939 return done;
1942 private Object TranslateToSpeculativeEarlyBindings(ILGenerator il, Type rtype, bool getObjectFromLateBindingInstance){
1943 //Find all members named this.name to which the current context might have access to.
1944 //Generate early bound access to these, guarded by runtime type checks.
1945 this.giveErrors = false;
1946 Object done = null;
1947 bool needObject = true;
1948 LocalBuilder objectLocal = null;
1949 Label next = il.DefineLabel();
1950 MemberInfoList members = this.GetAllKnownInstanceBindingsForThisName();
1951 for (int i = 0, n = members.count; i < n; i++){
1952 MemberInfo member = members[i];
1953 if (!(member is FieldInfo) && (!(member is PropertyInfo) ||
1954 ((PropertyInfo)member).GetIndexParameters().Length > 0 ||
1955 JSProperty.GetGetMethod((PropertyInfo)member, true) == null)) continue;
1956 this.member = member;
1957 if (!this.Accessible(false)) continue;
1958 if (needObject){
1959 needObject = false;
1960 if (getObjectFromLateBindingInstance){
1961 il.Emit(OpCodes.Dup);
1962 il.Emit(OpCodes.Ldfld, CompilerGlobals.objectField);
1963 }else
1964 this.TranslateToILObject(il, Typeob.Object, false);
1965 objectLocal = il.DeclareLocal(Typeob.Object);
1966 il.Emit(OpCodes.Stloc, objectLocal);
1967 done = il.DefineLabel();
1969 Type t = member.DeclaringType;
1970 il.Emit(OpCodes.Ldloc, objectLocal);
1971 il.Emit(OpCodes.Isinst, t);
1972 LocalBuilder objectTemp = il.DeclareLocal(t);
1973 il.Emit(OpCodes.Dup);
1974 il.Emit(OpCodes.Stloc, objectTemp);
1975 il.Emit(OpCodes.Brfalse_S, next);
1976 il.Emit(OpCodes.Ldloc, objectTemp);
1977 if (member is FieldInfo){
1978 FieldInfo field = (FieldInfo)member;
1979 if (field.IsLiteral){
1980 il.Emit(OpCodes.Pop);
1981 continue; //instance nested class, bail out.
1983 if (field is JSField)
1984 il.Emit(OpCodes.Ldfld, (FieldInfo)((JSField)field).GetMetaData());
1985 else if (field is JSFieldInfo)
1986 il.Emit(OpCodes.Ldfld, ((JSFieldInfo)field).field);
1987 else
1988 il.Emit(OpCodes.Ldfld, (FieldInfo)field);
1989 Convert.Emit(this, il, field.FieldType, rtype);
1990 }else if (member is PropertyInfo){
1991 MethodInfo getter = JSProperty.GetGetMethod((PropertyInfo)member, true);
1992 getter = this.GetMethodInfoMetadata(getter);
1993 if (getter.IsVirtual && !getter.IsFinal && (!t.IsSealed || t.IsValueType))
1994 il.Emit(OpCodes.Callvirt, getter);
1995 else
1996 il.Emit(OpCodes.Call, getter);
1997 Convert.Emit(this, il, getter.ReturnType, rtype);
1999 il.Emit(OpCodes.Br, (Label)done);
2000 il.MarkLabel(next);
2001 next = il.DefineLabel();
2003 il.MarkLabel(next);
2004 if (!needObject && !getObjectFromLateBindingInstance)
2005 il.Emit(OpCodes.Ldloc, objectLocal);
2006 this.member = null;
2007 return done;
2010 private Object TranslateToSpeculativeEarlyBoundCalls(ILGenerator il, Type rtype, ASTList argList, bool construct, bool brackets){
2011 this.giveErrors = false;
2012 Object done = null;
2013 bool needObject = true;
2014 LocalBuilder objectLocal = null;
2015 Label next = il.DefineLabel();
2016 IReflect[] classes = this.GetAllEligibleClasses();
2017 if (construct){
2018 //dealing with "new ob.foo(...)" or "new ob.foo[...]".
2019 //Early binding only makes sense if foo is a nested type marked as protected or package
2020 //But nested types are static and hence will not show up late bound via the object.
2021 //There is the possibility that a programmer can declare a static field and initialize it to a type.
2022 //In that case late bound access works if the field is public, but not otherwise.
2023 //This does not seem like a core scenario that justifies a lot of code inside this if statement.
2024 return done;
2026 Debug.Assert(argList.count == 0 || this.argIRs.Length == argList.count);
2027 foreach (IReflect c in classes){
2028 MemberInfo[] members = c.GetMember(this.name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
2029 try{
2030 // This code generation does not account for the case ob.foo(...) where ob.foo is a property
2031 // with zero arguments. The code should get the property followed by a call on the
2032 // returned object. For this case, we don't emit the speculative IL and let the late bound
2033 // code handle it.
2034 MethodInfo meth;
2035 MemberInfo mem = JSBinder.SelectCallableMember(members, this.argIRs);
2036 if (mem != null && mem.MemberType == MemberTypes.Property)
2038 ParameterInfo[] parameters;
2039 meth = ((PropertyInfo)mem).GetGetMethod(true);
2040 if (meth == null || (parameters = meth.GetParameters()) == null || parameters.Length == 0)
2041 continue;
2043 else
2044 meth = mem as MethodInfo;
2046 if (meth != null){
2047 if (!Binding.CheckParameters(meth.GetParameters(), this.argIRs, argList, this.context, 0, true, false))
2048 continue;
2049 //If meth is a base class method or if meth is an override of a base class method and the base class is in the same package as c
2050 //there is no need to have an instance check for c
2051 if (meth is JSFieldMethod){
2052 FunctionObject func = ((JSFieldMethod)meth).func;
2053 if (func != null && (func.attributes & MethodAttributes.NewSlot) == 0 && ((ClassScope)c).ParentIsInSamePackage())
2054 continue;
2055 }else if (meth is JSWrappedMethod && ((JSWrappedMethod)meth).obj is ClassScope && ((JSWrappedMethod)meth).GetPackage() == ((ClassScope)c).package)
2056 continue;
2057 this.member = meth;
2058 if (!this.Accessible(false)) continue;
2059 if (needObject){
2060 needObject = false;
2061 this.TranslateToILObject(il, Typeob.Object, false);
2062 objectLocal = il.DeclareLocal(Typeob.Object);
2063 il.Emit(OpCodes.Stloc, objectLocal);
2064 done = il.DefineLabel();
2066 Type t = meth.DeclaringType;
2067 il.Emit(OpCodes.Ldloc, objectLocal);
2068 il.Emit(OpCodes.Isinst, t);
2069 LocalBuilder objectTemp = il.DeclareLocal(t);
2070 il.Emit(OpCodes.Dup);
2071 il.Emit(OpCodes.Stloc, objectTemp);
2072 il.Emit(OpCodes.Brfalse, next);
2073 il.Emit(OpCodes.Ldloc, objectTemp);
2074 Binding.PlaceArgumentsOnStack(il, meth.GetParameters(), argList, 0, 0, Binding.ReflectionMissingCW);
2075 meth = this.GetMethodInfoMetadata(meth);
2076 if (meth.IsVirtual && !meth.IsFinal && (!t.IsSealed || t.IsValueType))
2077 il.Emit(OpCodes.Callvirt, meth);
2078 else
2079 il.Emit(OpCodes.Call, meth);
2080 Convert.Emit(this, il, meth.ReturnType, rtype);
2081 il.Emit(OpCodes.Br, (Label)done);
2082 il.MarkLabel(next);
2083 next = il.DefineLabel();
2085 }catch(AmbiguousMatchException){}
2087 il.MarkLabel(next);
2088 if (!needObject)
2089 il.Emit(OpCodes.Ldloc, objectLocal);
2090 this.member = null;
2091 return done;
2094 internal static void TranslateToStelem(ILGenerator il, Type etype){
2095 switch(Type.GetTypeCode(etype)){
2096 case TypeCode.SByte:
2097 case TypeCode.Boolean:
2098 case TypeCode.Byte:
2099 il.Emit(OpCodes.Stelem_I1); break;
2100 case TypeCode.Int16:
2101 case TypeCode.Char:
2102 case TypeCode.UInt16:
2103 il.Emit(OpCodes.Stelem_I2); break;
2104 case TypeCode.Int32:
2105 case TypeCode.UInt32:
2106 il.Emit(OpCodes.Stelem_I4); break;
2107 case TypeCode.Int64:
2108 case TypeCode.UInt64:
2109 il.Emit(OpCodes.Stelem_I8); break;
2110 case TypeCode.Single:
2111 il.Emit(OpCodes.Stelem_R4); break;
2112 case TypeCode.Double:
2113 il.Emit(OpCodes.Stelem_R8); break;
2114 case TypeCode.Decimal:
2115 case TypeCode.DateTime:
2116 case TypeCode.String:
2117 case TypeCode.Object:
2118 if (etype.IsValueType){
2119 il.Emit(OpCodes.Stobj, etype);
2120 }else
2121 il.Emit(OpCodes.Stelem_Ref);
2122 break;
2126 private void WarnIfNotFullyResolved(){
2127 if (this.isFullyResolved || this.member == null) return;
2128 if (this.member is JSVariableField && ((JSVariableField)this.member).type == null) return;
2129 if (!this.Engine.doFast && this.member is IWrappedMember) return;
2130 ScriptObject scope = Globals.ScopeStack.Peek();
2131 while (scope != null){
2132 if (scope is WithObject && !((WithObject)scope).isKnownAtCompileTime){
2133 this.context.HandleError(JSError.AmbiguousBindingBecauseOfWith);
2134 return;
2135 }else if (scope is ActivationObject && !((ActivationObject)scope).isKnownAtCompileTime){
2136 this.context.HandleError(JSError.AmbiguousBindingBecauseOfEval);
2137 return;
2139 scope = scope.GetParent();
2143 private void WarnIfObsolete(){
2144 Binding.WarnIfObsolete(this.member, this.context);
2147 internal static void WarnIfObsolete(MemberInfo member, Context context){
2148 if (member == null)
2149 return;
2150 String message = null;
2151 bool isError = false;
2152 Object[] custAttribs = CustomAttribute.GetCustomAttributes(member, typeof(ObsoleteAttribute), false);
2153 if (custAttribs != null && custAttribs.Length > 0){
2154 ObsoleteAttribute attr = (ObsoleteAttribute)custAttribs[0];
2155 message = attr.Message;
2156 isError = attr.IsError;
2157 }else{
2158 custAttribs = CustomAttribute.GetCustomAttributes(member, typeof(NotRecommended), false);
2159 if (custAttribs != null && custAttribs.Length > 0){
2160 NotRecommended attr = (NotRecommended)custAttribs[0];
2161 message = ": " + attr.Message;
2162 isError = false;
2163 }else
2164 return;
2166 context.HandleError(JSError.Deprecated, message, isError);
2170 private MethodInfo GetMethodInfoMetadata(MethodInfo method) {
2171 if (method is JSMethod)
2172 return ((JSMethod)method).GetMethodInfo(this.compilerGlobals);
2173 if (method is JSMethodInfo)
2174 return ((JSMethodInfo)method).method;
2175 return method;